package edu.gdkm.ssm.controller;

import edu.gdkm.ssm.domain.SysLog;
import edu.gdkm.ssm.service.ISysLogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;

@Component
@Aspect
public class LogAop {

    @Autowired
    private HttpServletRequest request;
    @Autowired
    private ISysLogService sysLogService;

    private Date startTime; // 开始时间
    private Class clazz; // 访问的类
    private Method method; // 访问的方法

    // 前置通知  主要是获取开始时间，执行的类是哪一个，执行的是哪一个方法
    @Before("execution(* edu.gdkm.ssm.controller.*.*(..))")
    public void doBefore(JoinPoint point) throws Exception {
        startTime = new Date(); // 访问时间
        // 获取访问的类
        clazz = point.getTarget().getClass();
        // 获取访问的方法名
        String methodName = point.getSignature().getName();
        // 获取访问的方法的参数
        Object[] args = point.getArgs();
        if(args == null || args.length == 0){
            // 获取无参数的方法
            method = clazz.getMethod(methodName);
        }else {
            // 有参数，则将args中的所有元素遍历，获取对应的class,装入Class[]数组中
            Class[] classes = new Class[args.length];
            for(int i = 0; i < args.length; i++){
                classes[i] = args[i].getClass();
            }
            // 获取有参方法
            method = clazz.getMethod(methodName, classes);
        }
    }

    @After("execution(* edu.gdkm.ssm.controller.*.*(..))")
    public void doAfter(JoinPoint point) throws Exception{
        if(clazz != SysLogController.class){
            String url = "";
            RequestMapping classAnnotation = (RequestMapping) clazz.getAnnotation(RequestMapping.class);
            if (classAnnotation != null) {
                // 获取方法上的@RequestMapping对象
                GetMapping getMapping = method.getAnnotation(GetMapping.class);
                PostMapping postMapping = method.getAnnotation(PostMapping.class);
                RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
                DeleteMapping deleteMapping = method.getAnnotation(DeleteMapping.class);
                if (getMapping != null) {
                    // 它的值应该是类上的@RequestMapping的value + 方法上的 @RequestMapping的value
                    url = classAnnotation.value()[0] + getMapping.value()[0];
                }
                if(postMapping != null){
                    url = classAnnotation.value()[0] + postMapping.value()[0];
                }
                if(requestMapping != null){
                    url = classAnnotation.value()[0] + requestMapping.value()[0];
                }
                if(deleteMapping != null){
                    url = classAnnotation.value()[0] + deleteMapping.value()[0];
                }
                SysLog sysLog = new SysLog();
                Long executionTime = new Date().getTime() - startTime.getTime();
                sysLog.setExecutionTime(executionTime);
                sysLog.setUrl(url);
                // 获取ip
                String ip = request.getRemoteAddr();
                sysLog.setIp(ip);
                // 可以通过securityContext获取，也可以从request.getSession中获取
                SecurityContext context = SecurityContextHolder.getContext();
                String username = ((User)(context.getAuthentication().getPrincipal())).getUsername();
                sysLog.setUsername(username);
                sysLog.setMethod(clazz.getName() + "." + method.getName());
                sysLog.setVisitTime(startTime);
                // 将日志信息保存到数据库
                this.sysLogService.save(sysLog);
            }
        }
    }

}
